package org.design.utils;

import lombok.SneakyThrows;
import org.design.snowFlake.SnowFlakeUtils;
import org.design.utils.entity.TreeData;
import org.junit.Test;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * CommonUtils
 *
 * @author 樊温军
 * @date 2025/6/17 上午9:04
 */
public class CommonUtils {

    /**
     * 判断字符串是否为空
     *
     * @param str 字符串
     * @return true:为空 false:不为空
     */
    public static boolean isBlank(String str) {
        return str == null || str.isEmpty();
    }

    /**
     * 判断对象是否为空
     *
     * @param obj 对象
     * @return true:为空 false:不为空
     */
    public static boolean isEmpty(Object obj) {
        return obj == null || obj.toString().isEmpty();
    }

    /**
     * 验证邮箱
     *
     * @param email 邮箱
     * @return true:是 false:否
     */
    public static boolean isEmail(String email) {
        String regex = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
        return email.matches(regex);
    }

    /**
     * 验证手机号
     *
     * @param mobile 手机号
     * @return true:是 false:否
     */
    public static boolean isMobile(String mobile) {
        String regex = "^((13[0-9])|(14[5,7])|(15[0-9])|(17[0-9])|(18[0-9]))\\d{8}$";
        return mobile.matches(regex);
    }

    /**
     * 列表转树结构
     *
     * @param list      列表
     * @param key       列表主键
     * @param parentKey 父级主键
     * @param childKey  子级主键
     * @param <T>       泛型
     * @return 树结构
     */
    @SneakyThrows
    public static <T> List<T> listToTree(List<T> list, String key, String parentKey, String childKey) {
        List<T> tree = new ArrayList<>();
        for (T t : list) {
            Class<?> clazz = t.getClass();
            Field parentValue = clazz.getDeclaredField(parentKey);
            parentValue.setAccessible(true);
            Object obj = parentValue.get(t);
            if (isEmpty(obj) || "0".equals(obj)) {
                tree.add(findChildren(t, list, key, parentKey, childKey));
            }
        }
        return tree;
    }

    /**
     * 递归查找子级
     *
     * @param p         父级
     * @param list      列表
     * @param key       列表主键
     * @param parentKey 父级主键
     * @param childKey  子级主键
     * @param <T>       泛型
     * @return 子级
     */
    @SneakyThrows
    private static <T> T findChildren(T p, List<T> list, String key, String parentKey, String childKey) {
        Class<?> clazz = p.getClass();
        Field value = clazz.getDeclaredField(key);
        value.setAccessible(true);
        Object id = value.get(p);
        if (isEmpty(id)) {
            throw new RuntimeException("主键不能为空");
        }
        Field childrenValue = clazz.getDeclaredField(childKey);
        childrenValue.setAccessible(true);
        Object children = childrenValue.get(p);
        if (isEmpty(children)) {
            List<T> childrenList = new ArrayList<>();
            childrenValue.set(p, childrenList);
        }
        for (T t : list) {
            Class<?> clazzT = t.getClass();
            Field parentValue = clazzT.getDeclaredField(parentKey);
            parentValue.setAccessible(true);
            Object parent = parentValue.get(t);
            if (!isEmpty(parent) && parent.equals(id)) {
                T tree = findChildren(t, list, key, parentKey, childKey);
                List<T> tList = (List<T>) childrenValue.get(p);
                tList.add(tree);
                childrenValue.set(p, tList);
            }
        }
        return p;
    }

    /**
     * 树结构转列表
     *
     * @param treeList 树结构
     * @param childKey 子级主键
     * @param <T>      泛型
     * @return 列表
     */
    @SneakyThrows
    public static <T> List<T> treeToList(List<T> treeList, String childKey) {
        List<T> list = new ArrayList<>();
        for (T t : treeList) {
            assignmentList(list, t, childKey);
        }
        return list;
    }

    /**
     * 递归赋值
     *
     * @param list     列表
     * @param t        树结构
     * @param childKey 子级主键
     * @param <T>      泛型
     */
    @SneakyThrows
    private static <T> void assignmentList(List<T> list, T t, String childKey) {
        list.add(t);
        Class<?> clazz = t.getClass();
        Field childrenValue = clazz.getDeclaredField(childKey);
        childrenValue.setAccessible(true);
        List<T> children = (List<T>) childrenValue.get(t);
        if (!isEmpty(children) && !children.isEmpty()) {
            for (T child : children) {
                assignmentList(list, child, childKey);
            }
            children.clear();
        }
    }

    /**
     * 时间转换
     *
     * @param time 时间
     * @return 时间字符串
     */
    public static String tranDate(LocalDateTime time, String... pattern) {
        if (pattern != null && pattern.length > 0) {
            return time.format(DateTimeFormatter.ofPattern(pattern[0]));
        }
        return time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

    @Test
    public void test() {
        for (int i = 0; i < 100000; i++) {
            long id = SnowFlakeUtils.getInstance().nextId();
            System.out.println(id);
        }
    }

    public static String getStackTrace(Exception e) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        e.printStackTrace(pw);
        return sw.toString();
    }

    private static void testTreeList() {
        TreeData treeData1 = new TreeData("1", "0", "爷爷", new ArrayList<>());
        TreeData treeData2 = new TreeData("2", "1", "大伯", new ArrayList<>());
        TreeData treeData3 = new TreeData("3", "1", "二伯", new ArrayList<>());
        TreeData treeData4 = new TreeData("4", "1", "父亲", new ArrayList<>());
        TreeData treeData5 = new TreeData("5", "1", "四叔", new ArrayList<>());
        TreeData treeData6 = new TreeData("6", "2", "大堂哥", new ArrayList<>());
        TreeData treeData7 = new TreeData("7", "3", "二堂哥", new ArrayList<>());
        TreeData treeData8 = new TreeData("8", "4", "我", new ArrayList<>());
        TreeData treeData9 = new TreeData("9", "5", "堂妹", new ArrayList<>());
        TreeData treeData10 = new TreeData("10", "6", "大侄子", new ArrayList<>());
        TreeData treeData11 = new TreeData("11", "6", "大侄女", new ArrayList<>());
        List<TreeData> list = new ArrayList<>();
        list.add(treeData1);
        list.add(treeData2);
        list.add(treeData3);
        list.add(treeData4);
        list.add(treeData5);
        list.add(treeData6);
        list.add(treeData7);
        list.add(treeData8);
        list.add(treeData9);
        list.add(treeData10);
        list.add(treeData11);
        List<TreeData> tree = listToTree(list, "id", "parentId", "children");
        System.out.println(tree);
        System.out.println(treeToList(tree, "children"));
    }
}
